/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.gameloft.glf;
/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


import android.content.Context;
import android.graphics.PixelFormat;
import android.util.Log;
import android.view.MotionEvent;

import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL10;

/**
 * A simple GLSurfaceView sub-class that demonstrate how to perform
 * OpenGL ES 2.0 rendering into a GL Surface. Note the following important
 * details:
 *
 * - The class must use a custom context factory to enable 2.0 rendering.
 *   See ContextFactory class definition below.
 *
 * - The class must use a custom EGLConfigChooser to be able to select
 *   an EGLConfig that supports 2.0. This is done by providing a config
 *   specification to eglChooseConfig() that has the attribute
 *   EGL10.ELG_RENDERABLE_TYPE containing the EGL_OPENGL_ES2_BIT flag
 *   set. See ConfigChooser class definition below.
 *
 * - The class must select the surface's format, then choose an EGLConfig
 *   that matches it exactly (with regards to red/green/blue/alpha channels
 *   bit depths). Failure to do so would result in an EGL_BAD_MATCH error.
 */
class GL2JNIView extends GLSurfaceView {
    private static String TAG = "GL2JNIView";
    private static final boolean DEBUG = false;
    private static int EGL_COVERAGE_BUFFERS_NV         = 0x30E0;
    private static int EGL_COVERAGE_SAMPLES_NV         = 0x30E1;
    private static int EGL_DEPTH_ENCODING_NV           = 0x30E2;
    private static int EGL_DEPTH_ENCODING_NONLINEAR_NV = 0x30E3;
	private static int EGL_OPENGL_ES2_BIT              = 4;

	private EGL10 mEgl = null;
	private EGLDisplay mDisplay = null;
	private EGLSurface mSurface = null;
	private EGLContext[] mContexts = null;
	private EGLSurface[] mSurfaces = null;

    public GL2JNIView(Context context, boolean translucent) {
        super(context);
    	setPreserveEGLContextOnPause(true);
        init(translucent);
    }

    private void init(boolean translucent) {

    	/* By default, GLSurfaceView() creates a RGB_565 opaque surface.
         * If we want a translucent one, we should change the surface's
         * format here, using PixelFormat.TRANSLUCENT for GL Surfaces
         * is interpreted as any 32-bit surface with alpha by SurfaceFlinger.
         */
        if (translucent) {
            this.getHolder().setFormat(PixelFormat.TRANSLUCENT);
        }

        /* Setup the context factory for 2.0 rendering.
         * See ContextFactory class definition below
         */
        setEGLContextFactory(new ContextFactory());
        
        /* Setup the window surface factory for 2.0 rendering.
         * See WindowSurfaceFactory class definition below
         */
        setEGLWindowSurfaceFactory(new WindowSurfaceFactory());
      
        /* We need to choose an EGLConfig that matches the format of
         * our surface exactly. This is going to be done in our
         * custom config chooser. See ConfigChooser class definition
         * below.
         */
        setEGLConfigChooser( new ConfigChooser() );

        /* Set the renderer responsible for frame rendering */
        setRenderer(new Renderer());
    }
    
    public boolean onTouchEvent(final MotionEvent event) {
    	final int action	= event.getAction();
    	final int mask		= (action&MotionEvent.ACTION_MASK);
		final int count		= event.getPointerCount();
		final int pointerId = (action&MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;

		final long eventtime = event.getEventTime();
		int a;

		if (action == MotionEvent.ACTION_MOVE) {
			a = 2;
			//System.out.println("------kush MotionEvent.ACTION_MOVE---------");
			for (int i=0; i<count; i++) {
				//System.out.println("------kush MotionEvent.ACTION_MOVE for loop id---------"+id);
				//System.out.println("------kush X--"+(int)event.getX(id)+"    Y--"+(int)event.getY(id));
				GL2JNILib.touchEvent(a,(int)event.getX(i), (int)event.getY(i), event.getPointerId(i));
			}
		}
		else {
			if (action == MotionEvent.ACTION_DOWN) {
				//System.out.println("------kush MotionEvent.ACTION_DOWN---------");
				a = 1;
			}
			else if (mask == MotionEvent.ACTION_POINTER_DOWN) {
				//System.out.println("------kush MotionEvent.ACTION_POINTER_DOWN---------");
				a = 1;
			}
			else if (mask == MotionEvent.ACTION_POINTER_UP) {
				//System.out.println("------kush MotionEvent.ACTION_POINTER_UP---------");
				a = 0;
			}
			else if (mask == MotionEvent.ACTION_UP) {
				//System.out.println("------kush MotionEvent.ACTION_UP---------");
				a = 0;
			}
			else {
				return true;
			}
			
			GL2JNILib.touchEvent(a,(int)event.getX(pointerId), (int)event.getY(pointerId), event.getPointerId(pointerId));
		}
		return true;
    }

    private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;

	private static int[] s_extraSurfaceAttribs2 = {
		EGL10.EGL_WIDTH, 1,
		EGL10.EGL_HEIGHT, 1,
		EGL10.EGL_NONE
	};

    private class ContextFactory implements GLSurfaceView.EGLContextFactory {

    	public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
            Log.w(TAG, "creating OpenGL ES 2.0 context(s)");
            checkEglError("Before eglCreateContext", egl);
            int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE};
            EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
			mDisplay = display;
			mEgl = egl;
			int extraContext = GL2JNILib.getNumExtraContext();
            if(checkEglError("After eglCreateContext", egl) && context != null) {
				mContexts = new EGLContext[extraContext + 1];
				mSurfaces = new EGLSurface[extraContext + 1];
				mContexts[0] = context;
				mSurfaces[0] = mSurface;

				int[] val = new int[1];
				int[] extraSurfaceAttribs = {
					EGL10.EGL_ALPHA_SIZE, 0,
					EGL10.EGL_RED_SIZE, 0,
					EGL10.EGL_GREEN_SIZE, 0,
					EGL10.EGL_BLUE_SIZE, 0,
					EGL10.EGL_DEPTH_SIZE, 0,
					EGL10.EGL_STENCIL_SIZE, 0,
					EGL10.EGL_RENDERABLE_TYPE, 0,
					EGL10.EGL_SURFACE_TYPE, EGL10.EGL_PBUFFER_BIT,
					EGL10.EGL_NONE
				};

				int last = 1;
				while(extraSurfaceAttribs[last] == 0)
				{
					egl.eglGetConfigAttrib(display, eglConfig, extraSurfaceAttribs[last - 1], val);
					extraSurfaceAttribs[last] = val[0];
					last += 2;
				}

				egl.eglChooseConfig(display, extraSurfaceAttribs, null, 0, val);
				EGLConfig extraConfig = null;
				if(checkEglError("After count config for extra", egl) && val[0] > 0) {
					EGLConfig[] configs = new EGLConfig[val[0]];
					egl.eglChooseConfig(display, extraSurfaceAttribs, configs, configs.length, val);
					if(!checkEglError("After choose config for extra", egl) || val[0] != configs.length) {
						throw new RuntimeException("something is terribly wrong");
					}
					last -= 2; // last is EGL_RENDERABLE_TYPE
					for(int c = 0; c < configs.length; ++c) {
						// we need an extra match for some attribute
						boolean ok = true;
						for(int i = 1; i < last; i += 2) {
							egl.eglGetConfigAttrib(display, configs[c], extraSurfaceAttribs[i - 1], val);
							if(val[0] != extraSurfaceAttribs[i]) {
								ok = false;
								break;
							}
						}
						if(ok) {
							egl.eglGetConfigAttrib(display, configs[c], extraSurfaceAttribs[last - 1], val);
							if((extraSurfaceAttribs[last] & val[0]) != 0)
							{
								extraConfig = configs[c];
								break;
							}
						}
					}
					if(extraConfig == null) {
						extraContext = 0;
					}
				} else {
					extraContext = 0;
				}

				for(int i = 0; i < extraContext;) {
					EGLSurface surf = egl.eglCreatePbufferSurface(display, extraConfig, s_extraSurfaceAttribs2);
					EGLContext ctx = null;
					boolean contextFailed = true;
					if(checkEglError("After eglCreatePbufferSurface for extra " + i, egl) &&
					   surf != null &&
					   surf != EGL10.EGL_NO_SURFACE) {
						ctx = egl.eglCreateContext(display, eglConfig, context, attrib_list);
						if(checkEglError("After eglCreateContext extra " + i, egl) &&
						   ctx != null &&
						   ctx != EGL10.EGL_NO_CONTEXT) {
							// try out the context to make sure its supported and valid
							boolean ok = mEgl.eglMakeCurrent(mDisplay, surf, surf, ctx);
							if(checkEglError("After try eglMakeCurrent for extra " + i, egl) && ok) {
								++i;
								mContexts[i] = ctx;
								mSurfaces[i] = surf;
								contextFailed = false;
							}
						}
					}
					if(contextFailed) {
						if(surf != null) {
							egl.eglDestroySurface(display, surf);
						}
						if(ctx != null) {
							egl.eglDestroyContext(display, ctx);
						}
						--extraContext;
					}
				}
				if(extraContext != mContexts.length - 1) {
					int cnt = extraContext + 1;
					EGLContext[] contexts = new EGLContext[cnt];
					EGLSurface[] surfaces = new EGLSurface[cnt];
					System.arraycopy(mContexts, 0, contexts, 0, cnt);
					System.arraycopy(mSurfaces, 0, surfaces, 0, cnt);
					GL2JNILib.setNumExtraContext(extraContext);
				}

				// restore state
				mEgl.eglMakeCurrent(mDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
			}
            Log.w(TAG, String.format("created 1 main OpenGL ES 2.0 context and %d extra OpenGL ES 2.0 context(s)", extraContext));
            return context;
        }

        public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {
			GL2JNILib.stateChanged(false);
			
			for(int i = 1; i < mContexts.length; ++i) {
	        	Log.w(TAG, String.format("destroying extra OpenGL ES 2.0 context number %d / %d", i, mContexts.length - 1));
				egl.eglDestroyContext(display, mContexts[i]);
				egl.eglDestroySurface(display, mSurfaces[i]);
			}
        	Log.w(TAG, "destroying main OpenGL ES 2.0 context");
            egl.eglDestroyContext(display, context);
			mContexts = null;
			mSurfaces = null;
			mDisplay = null;
			mEgl = null;
        	Log.w(TAG, "Done destroying contexts");
       }
    }

	public boolean setCurrentContext(int id) {
		try {
			boolean success = false;
			if(id < 0) {
				success = mEgl.eglMakeCurrent(mDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
				return success;
			}
			success = mEgl.eglMakeCurrent(mDisplay, mSurfaces[id], mSurfaces[id], mContexts[id]);
			checkEglError("setCurrentContext(" + id + ")", mEgl);
			if(!success) {
				// May be normal if the device doesn't support it.
				Log.e(TAG, "setCurrentContext(" + id + ") failed");
			}
			return success;
		} catch(Exception e) {
			Log.e(TAG, "exception caught in setCurrentContext:");
			Log.e(TAG, Log.getStackTraceString(e));
		}
		return false;
	}

	private static int s_eglErrorCount = 0;

    private static boolean checkEglError(String prompt, EGL10 egl) {
        int error;
		boolean ok = true;
		if(s_eglErrorCount == 0)
		{
			while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) {
				Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error));
				++s_eglErrorCount;
				if(s_eglErrorCount > 100) {
					Log.e(TAG, "eglGetError() bug detected! Further calls will be ignored (forced success)");
					return true;
				}
				ok = false;
			}
        }
		s_eglErrorCount = 0;
		return ok;
    }

    private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser {

        /* This EGL config specification is used to specify 2.0 rendering.
         * We use a minimum size of 4 bits for red/green/blue, but will
         * perform actual matching in chooseConfig() below.
         */
        private static int[] s_configAttribs_nonlinear =
        {
            EGL10.EGL_RED_SIZE, 4,
            EGL10.EGL_GREEN_SIZE, 4,
            EGL10.EGL_BLUE_SIZE, 4,
            EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
            EGL_DEPTH_ENCODING_NV, EGL_DEPTH_ENCODING_NONLINEAR_NV,
            EGL10.EGL_NONE
        };
        private static int[] s_configAttribs_default =
        {
            EGL10.EGL_RED_SIZE, 4,
            EGL10.EGL_GREEN_SIZE, 4,
            EGL10.EGL_BLUE_SIZE, 4,
            EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
            EGL10.EGL_NONE
        };

        public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {

			GL2JNILib.initGL();
        	GL2JNILib.getViewSettings();

			Log.w(TAG, "EGL Vendor" + egl.eglQueryString(display, EGL10.EGL_VENDOR));
			Log.w(TAG, "EGL Version: " + egl.eglQueryString(display, EGL10.EGL_VERSION));
			String exts = egl.eglQueryString(display, EGL10.EGL_EXTENSIONS);
			Log.w(TAG, "EGL Extensions:");
			java.util.StringTokenizer toks = new java.util.StringTokenizer(exts);
			boolean hasCoverageSampleNV = false;
			while(toks.hasMoreTokens())
			{
				String tok = toks.nextToken();
				Log.w(TAG, "\t" + tok);
				if(tok.equals("EGL_NV_coverage_sample")) {
					hasCoverageSampleNV = true;
				}
			}

			checkEglError("chooseConfig (init)", egl);

        	switch(GL2JNILib.mPixelSize) {
        	case 32: 
        		mRedSize = mGreenSize = mBlueSize = mAlphaSize = 8;
	          	break;
	          
        	case 24:
        		mRedSize = mGreenSize = mBlueSize = 8;
        		mAlphaSize = 0;
	          	break;
	         
        	default:
        		mRedSize = 5;
        		mGreenSize = 6;
        		mBlueSize = 5;
        		mAlphaSize = 0;
        	}
            mDepthSize = GL2JNILib.mDepthSize;
            mStencilSize = GL2JNILib.mStencilSize;
            mCSAA = GL2JNILib.mCSAA;
            
            /* Get the number of minimally matching EGL configurations
             */
            // nonlienar
            boolean useNonLinear = GL2JNILib.mDepthNonLinear == 1 ? true : false;
            int[] num_config = new int[1];
            egl.eglChooseConfig(display, s_configAttribs_nonlinear, null, 0, num_config);

			checkEglError("chooseConfig (get)", egl);

            int numConfigs = num_config[0];
            
            if(numConfigs <= 0 || useNonLinear == false) {
            	// OTHERS
            	useNonLinear = false;
                egl.eglChooseConfig(display, s_configAttribs_default, null, 0, num_config);

    			checkEglError("chooseConfig (get)", egl);

                numConfigs = num_config[0];
            }

            if (numConfigs <= 0) {
                throw new IllegalArgumentException("No configs match configSpec");
            }

            /* Allocate then read the array of minimally matching EGL configs
             */
            EGLConfig[] configs = new EGLConfig[numConfigs];
            if(useNonLinear) {
            	egl.eglChooseConfig(display, s_configAttribs_nonlinear, configs, numConfigs, num_config);
            } else {
            	egl.eglChooseConfig(display, s_configAttribs_default, configs, numConfigs, num_config);
            }

			checkEglError("chooseConfig (list)", egl);

            if (DEBUG)
                 printConfigs(egl, display, configs);

            /* Now return the "best" one
             */
            EGLConfig selectedConfig = chooseConfig(egl, display, configs, hasCoverageSampleNV);
            if (DEBUG) {
            	Log.w(TAG, "Selected config:\n");
                printConfig(egl, display, selectedConfig);
            }
            
			checkEglError("chooseConfig (end)", egl);

            return selectedConfig;
        }

        public EGLConfig chooseConfig(EGL10 egl,
									  EGLDisplay display,
									  EGLConfig[] configs,
									  boolean hasCoverageSampleNV) {
        	EGLConfig[] validConfigs = new EGLConfig[configs.length];
        	int validConfigCount = 0;
            //add all valid configs according to pixel component sizes
        	for(EGLConfig config : configs) {
                int d = findConfigAttrib(egl, display, config,
                        EGL10.EGL_DEPTH_SIZE, 0);
                int s = findConfigAttrib(egl, display, config,
                        EGL10.EGL_STENCIL_SIZE, 0);

                // We need at least mDepthSize and mStencilSize bits
                if (d < mDepthSize || s < mStencilSize)
                    continue;

                // We want an *exact* match for red/green/blue/alpha
                int r = findConfigAttrib(egl, display, config,
                        EGL10.EGL_RED_SIZE, 0);
                int g = findConfigAttrib(egl, display, config,
                            EGL10.EGL_GREEN_SIZE, 0);
                int b = findConfigAttrib(egl, display, config,
                            EGL10.EGL_BLUE_SIZE, 0);
                int a = findConfigAttrib(egl, display, config,
                        EGL10.EGL_ALPHA_SIZE, 0);                       

                if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize)
                	validConfigs[validConfigCount++] = config;
            }
        	if (validConfigCount == 0)
        		return null;
        	//choose the best config according to CSAA requirement
        	EGLConfig bestConfig = validConfigs[0];
        	int minDistanceCSAA = java.lang.Integer.MAX_VALUE;
            for (int i = 0; i < validConfigCount; ++i) {
            	EGLConfig config = validConfigs[i];
            	int csaa = (hasCoverageSampleNV
							? (findConfigAttrib(egl, display, config, EGL_COVERAGE_BUFFERS_NV, 0) *
							   findConfigAttrib(egl, display, config, EGL_COVERAGE_SAMPLES_NV, 0))
							: 0);
            	if (mCSAA == csaa) { //best config
            		return config;
				} else if (csaa > 0 && java.lang.Math.abs(csaa - mCSAA) < minDistanceCSAA)  { //choose the nearest value 
        			bestConfig = config;
        			minDistanceCSAA = java.lang.Math.abs(csaa - mCSAA);
            	}
            }
            return bestConfig;
        }

        private int findConfigAttrib(EGL10 egl, EGLDisplay display,
                EGLConfig config, int attribute, int defaultValue) {

            if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
                return mValue[0];
            }
            return defaultValue;
        }

        private void printConfigs(EGL10 egl, EGLDisplay display,
            EGLConfig[] configs) {
            int numConfigs = configs.length;
            Log.w(TAG, String.format("%d configurations\n", numConfigs));
            for (int i = 0; i < numConfigs; i++) {
                Log.w(TAG, String.format("Configuration %d:\n", i));
                printConfig(egl, display, configs[i]);
            }
        }

		private static final int[] s_configAttributes = {
			EGL10.EGL_BUFFER_SIZE,
			EGL10.EGL_ALPHA_SIZE,
			EGL10.EGL_BLUE_SIZE,
			EGL10.EGL_GREEN_SIZE,
			EGL10.EGL_RED_SIZE,
			EGL10.EGL_DEPTH_SIZE,
			EGL10.EGL_STENCIL_SIZE,
			EGL10.EGL_CONFIG_CAVEAT,
			EGL10.EGL_CONFIG_ID,
			EGL10.EGL_LEVEL,
			EGL10.EGL_MAX_PBUFFER_HEIGHT,
			EGL10.EGL_MAX_PBUFFER_PIXELS,
			EGL10.EGL_MAX_PBUFFER_WIDTH,
			EGL10.EGL_NATIVE_RENDERABLE,
			EGL10.EGL_NATIVE_VISUAL_ID,
			EGL10.EGL_NATIVE_VISUAL_TYPE,
			0x3030, // EGL10.EGL_PRESERVED_RESOURCES,
			EGL10.EGL_SAMPLES,
			EGL10.EGL_SAMPLE_BUFFERS,
			EGL10.EGL_SURFACE_TYPE,
			EGL10.EGL_TRANSPARENT_TYPE,
			EGL10.EGL_TRANSPARENT_RED_VALUE,
			EGL10.EGL_TRANSPARENT_GREEN_VALUE,
			EGL10.EGL_TRANSPARENT_BLUE_VALUE,
			0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB,
			0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA,
			0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL,
			0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL,
			EGL10.EGL_LUMINANCE_SIZE,
			EGL10.EGL_ALPHA_MASK_SIZE,
			EGL10.EGL_COLOR_BUFFER_TYPE,
			EGL10.EGL_RENDERABLE_TYPE,
			0x3042, // EGL10.EGL_CONFORMANT,
			EGL_COVERAGE_BUFFERS_NV,
			EGL_COVERAGE_SAMPLES_NV
		};

		private static final String[] s_names = {
			"EGL_BUFFER_SIZE",
			"EGL_ALPHA_SIZE",
			"EGL_BLUE_SIZE",
			"EGL_GREEN_SIZE",
			"EGL_RED_SIZE",
			"EGL_DEPTH_SIZE",
			"EGL_STENCIL_SIZE",
			"EGL_CONFIG_CAVEAT",
			"EGL_CONFIG_ID",
			"EGL_LEVEL",
			"EGL_MAX_PBUFFER_HEIGHT",
			"EGL_MAX_PBUFFER_PIXELS",
			"EGL_MAX_PBUFFER_WIDTH",
			"EGL_NATIVE_RENDERABLE",
			"EGL_NATIVE_VISUAL_ID",
			"EGL_NATIVE_VISUAL_TYPE",
			"EGL_PRESERVED_RESOURCES",
			"EGL_SAMPLES",
			"EGL_SAMPLE_BUFFERS",
			"EGL_SURFACE_TYPE",
			"EGL_TRANSPARENT_TYPE",
			"EGL_TRANSPARENT_RED_VALUE",
			"EGL_TRANSPARENT_GREEN_VALUE",
			"EGL_TRANSPARENT_BLUE_VALUE",
			"EGL_BIND_TO_TEXTURE_RGB",
			"EGL_BIND_TO_TEXTURE_RGBA",
			"EGL_MIN_SWAP_INTERVAL",
			"EGL_MAX_SWAP_INTERVAL",
			"EGL_LUMINANCE_SIZE",
			"EGL_ALPHA_MASK_SIZE",
			"EGL_COLOR_BUFFER_TYPE",
			"EGL_RENDERABLE_TYPE",
			"EGL_CONFORMANT",
			"EGL_COVERAGE_BUFFERS_NV",
			"EGL_COVERAGE_SAMPLES_NV"
		};

        private void printConfig(EGL10 egl, EGLDisplay display,
                EGLConfig config) {
            int[] value = new int[1];
            for (int i = 0; i < s_configAttributes.length; i++) {
                int attribute = s_configAttributes[i];
                String name = s_names[i];
                if ( egl.eglGetConfigAttrib(display, config, attribute, value)) {
                    Log.w(TAG, String.format("  %s: %d\n", name, value[0]));
                } else {
                    // Log.w(TAG, String.format("  %s: failed\n", name));
                    while (egl.eglGetError() != EGL10.EGL_SUCCESS);
                }
            }
        }

        // Subclasses can adjust these values:
        protected int mRedSize;
        protected int mGreenSize;
        protected int mBlueSize;
        protected int mAlphaSize;
        protected int mDepthSize;
        protected int mStencilSize;
        protected int mCSAA;
        private int[] mValue = new int[1];
    }

    private class WindowSurfaceFactory implements GLSurfaceView.EGLWindowSurfaceFactory {
    
    	public EGLSurface createWindowSurface (EGL10 egl, EGLDisplay display, EGLConfig config, Object nativeWindow) { 
			checkEglError("Before create window", egl);
			EGLSurface surface = egl.eglCreateWindowSurface(display, config, nativeWindow, null);
			checkEglError("After create window", egl);
			mSurface = surface;
			if(mSurfaces != null) {
				mSurfaces[0] = surface;
			}
			return surface;
    	} 
    	
    	public void destroySurface (EGL10 egl, EGLDisplay display, EGLSurface surface) {
    		egl.eglDestroySurface(display, surface);
			mSurface = null;
			if(mSurfaces != null) {
				mSurfaces[0] = null;
			}
    	}

    }
    
    private static class Renderer implements GLSurfaceView.Renderer {
        public void onDrawFrame(GL10 gl) {
            GL2JNILib.step();
        }

        public void onSurfaceChanged(GL10 gl, int width, int height) {
        	Log.e(TAG, String.format("Renderer::onSurfaceChanged(%d, %d)", width, height));
        	GL2JNILib.resize(width, height);
        }

        public void onSurfaceCreated(GL10 gl, EGLConfig config) {        	
        	Log.e(TAG, String.format("Renderer::onSurfaceCreated()"));
        	GL2JNILib.stateChanged(true);
        }

        public void onSurfaceLost() {
        	Log.e(TAG, String.format("Renderer::onSurfaceLost()"));
        }
    }
}

